/*
 * Copyright 2008 Zoundry LLC, Inc.  All Rights Reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 */
package org.zoundry.gaedt.core.models.application;

import java.util.List;
import org.eclipse.core.resources.IProject;
import test.org.zoundry.gaedt.core.ZGaeCoreTestCase;

/**
 * Test case for the gae application model.
 */
public class ZGaeApplicationModelTest extends ZGaeCoreTestCase
{
    /**
     * Tests the application model.
     *
     * @throws Exception
     */
    public void testEmptyApplicationModel() throws Exception
    {
        IProject project = createTestProject("ZGaeApplicationModelTest_testEmptyApplicationModel");

        ZGaeApplicationModel model = new ZGaeApplicationModel(project);
        assertNotNull(model);
        assertModelIsEmpty(model);

        populateBaseModelInfo(model);
        populateHandlerModelInfo(model);
        populateDevModelInfo(model);

        assertModelBaseSettings(model);
        assertHandlerSettings(model);
        assertModelDevSettings(model);
    }

    /**
     * Tests the application model save/load.
     *
     * @throws Exception
     */
    public void testApplicationModelIO() throws Exception
    {
        IProject project = createTestProject("ZGaeApplicationModelTest_testApplicationModelIO");

        ZGaeApplicationModel model = new ZGaeApplicationModel(project);
        assertNotNull(model);

        populateBaseModelInfo(model);
        populateHandlerModelInfo(model);
        populateDevModelInfo(model);

        model.save();

        model = new ZGaeApplicationModel(project);
        assertNotNull(model);
        assertModelBaseSettings(model);
        assertHandlerSettings(model);
        assertModelDevSettings(model);
    }

    /**
     * Tests the application model's 'move' method.
     *
     * @throws Exception
     */
    public void testHandlerMovement() throws Exception
    {
        IProject project = createTestProject("ZGaeApplicationModelTest_testHandlerMovement");

        ZGaeApplicationModel model = new ZGaeApplicationModel(project);
        assertNotNull(model);
        assertModelIsEmpty(model);

        populateHandlerModelInfo(model);

        assertHandlerSettings(model);

        // Move 0 spaces - should not change the model.
        model.move(model.getHandlers().get(2), 0);
        assertHandlerSettings(model);

        // Move the handler 2 places earlier in the list
        IZGaeHandlerModel handler = model.getHandlers().get(2);
        model.move(handler, -2);
        // Handler should now be in position 0
        assertEquals(handler, model.getHandlers().get(0));

        // Move the handler 1 place later in the list
        handler = model.getHandlers().get(0);
        model.move(handler, 1);
        // Handler should now be in position 1
        assertEquals(handler, model.getHandlers().get(1));
    }

    /**
     * Tests the application model's 'removeHandler' method.
     *
     * @throws Exception
     */
    public void testHandlerRemove() throws Exception
    {
        IProject project = createTestProject("ZGaeApplicationModelTest_testHandlerRemove");

        ZGaeApplicationModel model = new ZGaeApplicationModel(project);
        assertNotNull(model);
        assertModelIsEmpty(model);

        populateHandlerModelInfo(model);

        assertHandlerSettings(model);

        // Remove the first handler
        model.removeHandler(0);
        assertEquals(2, model.getHandlers().size());
    }

    /**
     * Tests the application model's 'insertHandler' method.
     *
     * @throws Exception
     */
    public void testHandlerInsert() throws Exception
    {
        IProject project = createTestProject("ZGaeApplicationModelTest_testHandlerInsert");

        ZGaeApplicationModel model = new ZGaeApplicationModel(project);
        assertNotNull(model);
        assertModelIsEmpty(model);

        populateHandlerModelInfo(model);

        assertHandlerSettings(model);

        // Remove the first handler
        ZGaeScriptHandlerModel insertedHandler = new ZGaeScriptHandlerModel();
        insertedHandler.setUrl("/inserted");
        model.insertHandler(1, insertedHandler);
        assertEquals(4, model.getHandlers().size());

        IZGaeHandlerModel handlerModel = model.getHandlers().get(3);
        assertEquals("/item-(.*?)/category-(.*)", handlerModel.getUrl());
    }

    /**
     * Populate the model with some info.
     *
     * @param aModel
     */
    protected void populateBaseModelInfo(ZGaeApplicationModel aModel)
    {
        aModel.setName("testApp");
        aModel.setRuntimeType("python");
        aModel.setApiVersion(5);
        aModel.setVersion(3);
        aModel.setDefaultExpiration("4d 12h");
    }

    /**
     * Populate the model with some handlers.
     *
     * @param aModel
     */
    protected void populateHandlerModelInfo(ZGaeApplicationModel aModel)
    {
        ZGaeScriptHandlerModel scriptHandlerModel = new ZGaeScriptHandlerModel();
        scriptHandlerModel.setUrl("/test");
        scriptHandlerModel.setScript("test.py");
        scriptHandlerModel.setLogin(TZGaeHandlerLoginType.Admin);
        aModel.addHandler(scriptHandlerModel);

        ZGaeStaticDirectoryHandlerModel staticHandlerModel = new ZGaeStaticDirectoryHandlerModel();
        staticHandlerModel.setUrl("/test_static");
        staticHandlerModel.setStaticDir("/test/test_dir");
        staticHandlerModel.setExpiration("4d 5h");
        staticHandlerModel.setMimeType("text/plain");
        aModel.addHandler(staticHandlerModel);

        ZGaeStaticFilePatternHandlerModel staticFilesHandlerModel = new ZGaeStaticFilePatternHandlerModel();
        staticFilesHandlerModel.setUrl("/item-(.*?)/category-(.*)");
        staticFilesHandlerModel.setStaticFiles("archives/\\2/items/\\1");
        staticFilesHandlerModel.setLogin(TZGaeHandlerLoginType.Admin);
        staticFilesHandlerModel.setExpiration("7d");
        staticFilesHandlerModel.setMimeType("image/jpeg");
        staticFilesHandlerModel.setUpload("archives/(.*?)/items/(.*)");
        aModel.addHandler(staticFilesHandlerModel);
    }

    /**
     * Populate the model with some dev settings.
     *
     * @param aModel
     */
    protected void populateDevModelInfo(ZGaeApplicationModel aModel)
    {
        aModel.setDevAddress("0.0.0.0");
        aModel.setDevAuthDomain("mydomain.com");
        aModel.setDevDebug(true);
        aModel.setDevDebugImports(true);
        aModel.setDevDisableStaticCaching(true);
        aModel.setDevEnableSendmail(true);
        aModel.setDevPort(8088);
        aModel.setDevRequireIndexes(true);
        aModel.setDevShowMailBody(true);
        aModel.setDevSMTPHost("mysmtphost.com");
        aModel.setDevSMTPPassword("mypassword");
        aModel.setDevSMTPPort(8877);
        aModel.setDevSMTPUser("myuser");
    }

    /**
     * Asserts that the model is empty.
     *
     * @param aModel
     */
    protected void assertModelIsEmpty(ZGaeApplicationModel aModel)
    {
        assertEquals("", aModel.getName());
        assertEquals("", aModel.getRuntimeType());
        assertEquals(1, aModel.getApiVersion());
        assertEquals(1, aModel.getVersion());
        assertEquals("", aModel.getDevAddress());
        assertEquals("", aModel.getDevAuthDomain());
        assertEquals(false, aModel.isDevDebug());
        assertEquals(false, aModel.isDevDebugImports());
        assertEquals(false, aModel.isDevDisableStaticCaching());
        assertEquals(false, aModel.isDevEnableSendmail());
        assertEquals(8080, aModel.getDevPort());
        assertEquals(false, aModel.isDevRequireIndexes());
        assertEquals(false, aModel.isDevShowMailBody());
        assertEquals("", aModel.getDevSMTPHost());
        assertEquals("", aModel.getDevSMTPPassword());
        assertEquals(25, aModel.getDevSMTPPort());
        assertEquals("", aModel.getDevSMTPUser());
    }

    /**
     * Asserts that the model has the correct base settings.
     *
     * @param aModel
     */
    protected void assertModelBaseSettings(ZGaeApplicationModel aModel)
    {
        assertEquals("testApp", aModel.getName());
        assertEquals("python", aModel.getRuntimeType());
        assertEquals(5, aModel.getApiVersion());
        assertEquals(3, aModel.getVersion());
        assertEquals("4d 12h", aModel.getDefaultExpiration());
    }

    /**
     * Asserts that the model has the correct handler setings.
     *
     * @param aModel
     */
    protected void assertHandlerSettings(ZGaeApplicationModel aModel)
    {
        List<IZGaeHandlerModel> handlers = aModel.getHandlers();
        assertEquals("Expected two handlers.", 3, handlers.size());

        IZGaeHandlerModel handlerModel = handlers.get(0);
        assertTrue(handlerModel instanceof ZGaeScriptHandlerModel);
        ZGaeScriptHandlerModel scriptHandlerModel = (ZGaeScriptHandlerModel) handlerModel;
        assertEquals("/test", scriptHandlerModel.getUrl());
        assertEquals("test.py", scriptHandlerModel.getScript());
        assertEquals(TZGaeHandlerLoginType.Admin, scriptHandlerModel.getLogin());

        handlerModel = handlers.get(1);
        assertTrue(handlerModel instanceof ZGaeStaticDirectoryHandlerModel);
        ZGaeStaticDirectoryHandlerModel staticHandlerModel = (ZGaeStaticDirectoryHandlerModel) handlerModel;
        assertEquals("/test_static", staticHandlerModel.getUrl());
        assertEquals("/test/test_dir", staticHandlerModel.getStaticDir());
        assertEquals(TZGaeHandlerLoginType.None, staticHandlerModel.getLogin());
        assertEquals("4d 5h", staticHandlerModel.getExpiration());
        assertEquals("text/plain", staticHandlerModel.getMimeType());

        handlerModel = handlers.get(2);
        assertTrue(handlerModel instanceof ZGaeStaticFilePatternHandlerModel);
        ZGaeStaticFilePatternHandlerModel staticFilesHandlerModel = (ZGaeStaticFilePatternHandlerModel) handlerModel;
        assertEquals("/item-(.*?)/category-(.*)", staticFilesHandlerModel.getUrl());
        assertEquals("archives/\\2/items/\\1", staticFilesHandlerModel.getStaticFiles());
        assertEquals(TZGaeHandlerLoginType.Admin, staticFilesHandlerModel.getLogin());
        assertEquals("7d", staticFilesHandlerModel.getExpiration());
        assertEquals("image/jpeg", staticFilesHandlerModel.getMimeType());
        assertEquals("archives/(.*?)/items/(.*)", staticFilesHandlerModel.getUpload());
    }

    /**
     * Asserts that the model has the correct dev settings.
     *
     * @param aModel
     */
    protected void assertModelDevSettings(ZGaeApplicationModel aModel)
    {
        assertEquals("0.0.0.0", aModel.getDevAddress());
        assertEquals("mydomain.com", aModel.getDevAuthDomain());
        assertEquals(true, aModel.isDevDebug());
        assertEquals(true, aModel.isDevDebugImports());
        assertEquals(true, aModel.isDevDisableStaticCaching());
        assertEquals(true, aModel.isDevEnableSendmail());
        assertEquals(8088, aModel.getDevPort());
        assertEquals(true, aModel.isDevRequireIndexes());
        assertEquals(true, aModel.isDevShowMailBody());
        assertEquals("mysmtphost.com", aModel.getDevSMTPHost());
        assertEquals("mypassword", aModel.getDevSMTPPassword());
        assertEquals(8877, aModel.getDevSMTPPort());
        assertEquals("myuser", aModel.getDevSMTPUser());
    }
}
